<?php

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Capsule\Manager as DB;

class memberwalletapplyModel extends Model
{
    protected $table = 'member_wallet_apply';
    protected $primaryKey = 'id';
    protected $appends = [
        'status_text',
        'apply_type_text',
    ];
    protected $hidden = ['actual_money', 'log', 'payment_json', 'updatetime'];

    public $timestamps = false;

    protected function serializeDate(DateTimeInterface $date)
    {
        return $date->format('Y-m-d H:i:s');
    }

    /**
     * 获取提现单号
     *
     * @param int $user_id
     * @return string
     */
    public static function getSn($user_id)
    {
        $rand = $user_id < 9999 ? mt_rand(100000, 99999999) : mt_rand(100, 99999);
        $order_sn = date('Yhis') . $rand;

        $id = str_pad($user_id, (24 - strlen($order_sn)), '0', STR_PAD_BOTH);

        return 'W' . $order_sn . $id;
    }

    // 提现记录
    public static function getList($params)
    {
        $user = \app\service\auth::getUser();
        $page = $params['page'] ?? 1;
        $per_page = $params['per_page'] ?? 10;

        $total = self::where('member_id', $user->id)->count();
        $data = self::where('member_id', $user->id)
            ->orderBy('id', 'desc')
            ->offset(($page - 1) * $per_page)
            ->limit($per_page)
            ->get();

        $list = [];
        foreach ($data as $item) {
            $item->createtime = strtotime($item->created_at);
            $list[] = $item;
        }

        $walletApplys = [
            'current_page' => $page,
            'last_page' => ceil($total / $per_page),
            'per_page' => $per_page,
            'total' => $total,
            'data' => $list,
        ];

        return $walletApplys;
    }

    /**
     * 申请提现
     *
     * @param int $type 提现方式 wechat|alipay|bank
     * @param int $money 提现金额
     */
    public static function apply($type, $money)
    {
        $user = \app\service\auth::getUser();
        $config = self::getWithdrawConfig();
        if (!in_array($type, $config['methods'])) {
            throw new Exception('暂不支持该提现方式');
        }

        $min = round(floatval($config['min']), 2);
        $max = round(floatval($config['max']), 2);
        $service_fee = round(floatval($config['service_fee'] / 100), 3);      // 三位小数

        // 检查最小提现金额
        if ($money < $min || $money <= 0) {
            throw new Exception('提现金额不能少于 ' . $min . '元');
        }
        // 检查最大提现金额
        if ($max && $money > $max) {
            throw new Exception('提现金额不能大于 ' . $max . '元');
        }

        // 计算手续费
        $charge = $money * $service_fee;
        if ($user->money < $money) {
            throw new Exception('可提现余额不足');
        }

        // 检查提现账户信息
        $bank = memberbankModel::info($type, false);

        // 添加提现记录
        $platform = getHeader('platform');

        $apply['apply_sn'] = self::getSn($user->id);
        $apply['member_id'] = $user->id;
        $apply['money'] = $money;
        $apply['charge_money'] = $charge;
        $apply['service_fee'] = $service_fee;
        $apply['apply_type'] = $type;
        $apply['platform'] = $platform;
        $apply['created_at'] = timestamp();
        switch ($type) {
            case 'wechat':
                $applyInfo = [
                    '微信用户' => $bank['real_name'],
                    '微信ID' => $bank['card_no'],
                ];
                break;
            case 'alipay':
                $applyInfo = [
                    '真实姓名'  => $bank['real_name'],
                    '支付宝账户' => $bank['card_no']
                ];
                break;
            case 'bank':
                $applyInfo = [
                    '真实姓名' => $bank['real_name'],
                    '开户行'  => $bank['bank_name'],
                    '省'    => $bank['province'],
                    '市'    => $bank['city'],
                    '支行名称' => $bank['branch_name'],
                    '银行卡号' => $bank['card_no'],
                ];
                break;
        }
        if (!isset($applyInfo)) {
            throw new Exception('您的提现信息有误');
        }

        $apply['apply_info'] = json_encode($applyInfo, JSON_UNESCAPED_UNICODE);
        $apply['status'] = 0;
        $apply['id'] = self::insertGetId($apply);

        // return $apply;

        $apply = self::find($apply['id']);
        self::handleLog($apply, 'apply');
        // 扣除用户余额
        memberModel::money(-($money), $user->id, 'withdrawapply', $apply->id);

        // 检查是否执行自动打款
        $autoCheck = false;
        if ($type !== 'bank' && $config['wechat_alipay_auto']) {
            $autoCheck = true;
        }

        if ($autoCheck) {
            $apply = self::handleAgree($apply);
            $apply = self::handleWithdraw($apply);
        }

        return $apply;
    }

    public static function handleLog($apply, $event, $msg = '')
    {
        switch ($event) {
            case 'apply':
                $remark = '用户发起提现申请';
                break;
            case 'reject':
                $remark = '拒绝提现申请';
                break;
            case 'agree':
                $remark = '同意提现申请';
                break;
            case 'finished':
                $remark = '已打款';
                break;
            default:
                break;
        }
        $oper = \app\service\auth::setOper();
        $log = new memberwalletapplylogModel();
        $log->apply_id = $apply->id;
        $log->event = $event;
        $log->remark = ($remark ?? '') . ($msg ? "({$msg})" : '');
        $log->oper_type = $oper['oper_type'];
        $log->oper_id = $oper['oper_id'];
        $log->created_at = timestamp();
        $log->save();
    }

    // 同意
    public static function handleAgree($apply)
    {
        if ($apply->status != 0) {
            throw new Exception('请勿重复操作');
        }
        $apply->status = 1;
        $apply->save();
        self::handleLog($apply, 'agree');
        return $apply;
    }

    // 处理打款
    public static function handleWithdraw($apply)
    {
        if ($apply->status != 1) {
            throw new Exception('请勿重复操作');
        }
        if ($apply->apply_type !== 'bank') {
            $withDrawStatus = self::handleTransfer($apply);
        } else {
            $withDrawStatus = true;
        }
        if ($withDrawStatus) {
            $apply->status = 2;
            $apply->actual_money = round($apply->money - $apply->charge_money, 2);
            $apply->save();
            self::handleLog($apply, 'finished');
        }
        return $apply;
    }

    // 拒绝
    public static function handleReject($apply, $rejectInfo)
    {
        if ($apply->status != 0 && $apply->status != 1) {
            throw new Exception('请勿重复操作');
        }
        $apply->status = -1;
        $apply->save();
        memberModel::money($apply->money, $apply->member_id, 'withdrawdenied', $apply->id);
        self::handleLog($apply, 'reject', $rejectInfo);
    }

    // 企业付款提现
    private static function handleTransfer($apply)
    {
        $type = $apply->apply_type;
        $platform = $apply->platform;
        // 1.企业自动付款
        $pay = new PayService($type, $platform, '');

        // 2.组装数据
        if ($type == 'wechat') {
            $payload = [
                'partner_trade_no' => $apply->apply_sn,
                'openid'           => $apply->apply_info['微信ID'],
                'check_name'       => 'NO_CHECK',
                'amount'           => $apply->money,
                'desc'             => "用户[{$apply->apply_info['微信用户']}]提现"
            ];
        } elseif ($type == 'alipay') {
            $payload = [
                'out_biz_no'   => $apply->apply_sn,
                'trans_amount' => $apply->money,
                'product_code' => 'TRANS_ACCOUNT_NO_PWD',
                'biz_scene'    => 'DIRECT_TRANSFER',
                // 'order_title' => '余额提现到',
                'remark'       => '用户提现',
                'payee_info'   => [
                    'identity'      => $apply->apply_info['支付宝账户'],
                    'identity_type' => 'ALIPAY_LOGON_ID',
                    'name'          => $apply->apply_info['真实姓名'],
                ]
            ];
        }

        // 3.发起付款
        try {
            list($code, $response) = $pay->transfer($payload);
            if ($code === 1) {
                $apply->payment_json = json_encode($response, JSON_UNESCAPED_UNICODE);
                $apply->save();
                return true;
            }
        } catch (Exception $e) {
            Log::out('提现失败：' . ' 行号：' . $e->getLine() . '文件：' . $e->getFile() . '错误信息：' . $e->getMessage(), 'error');
            throw new Exception($e->getMessage());
        }
        return false;
    }


    /**
     * 提现类型列表
     */
    public function getApplyTypeList()
    {
        return ['bank' => '银行卡', 'wechat' => '微信零钱', 'alipay' => '支付宝账户'];
    }


    /**
     * 提现类型中文
     */
    public function getApplyTypeTextAttribute()
    {
        $value = isset($this->attributes['apply_type']) ? $this->attributes['apply_type'] : '';
        $list = $this->getApplyTypeList();
        return isset($list[$value]) ? $list[$value] : '';
    }

    /**
     * 提现信息
     */
    public function getApplyInfoAttribute()
    {
        $value = isset($this->attributes['apply_info']) ? $this->attributes['apply_info'] : $value;
        return json_decode($value, true);
    }

    /**
     * 提现信息 格式转换
     */
    public function setApplyInfoAttribute()
    {
        $value = isset($this->attributes['apply_info']) ? $this->attributes['apply_info'] : $value;
        $applyInfo = json_encode($value, JSON_UNESCAPED_UNICODE);
        return $applyInfo;
    }

    public function getStatusTextAttribute()
    {
        switch ($this->attributes['status']) {
            case 0:
                $status_name = '审核中';
                break;
            case 1:
                $status_name = '处理中';
                break;
            case 2:
                $status_name = '已处理';
                break;
            case -1:
                $status_name = '已拒绝';
                break;
            default:
                $status_name = '';
        }

        return $status_name;
    }

    public static function getWithdrawConfig($inner = false)
    {
        $config = configModel::query()->where('type', 9)->pluck('value', 'key')->toArray();
        $new_mode = [];
        if(!empty($config['withdraw_mode'])){
            $withdraw_mode = json_decode($config['withdraw_mode'], true);
            foreach ($withdraw_mode as $mode){
                if ($mode === '微信零钱'){
                    array_push($new_mode, 'weixin');
                }elseif ($mode === '支付宝'){
                    array_push($new_mode, 'alipay');
                }elseif ($mode === '手动线下打款'){
                    array_push($new_mode, 'bank');
                }
            }
            unset($mode, $withdraw_mode);
        }
        if($inner){
            return [
                'enable_withdraw' => $config['enable_withdraw']??0,
                'min' => $config['withdraw_min']??0,
                'max' => $config['withdraw_max']??0,
                'methods' => $new_mode,
                'service_fee' => $config['service_fee']??0,
                'wechat_alipay_auto' => false,
                'withdraw_enbale_goods' => $config['withdraw_enbale_goods']??'',
                'enable_transfer' => $config['enable_transfer']??0,
                'withdraw_exception' => $config['withdraw_exception']??'',
                'withdraw_base_money'=>$config['withdraw_base_money']??0,
            ];
        }else{
            return [
                'enable_withdraw' => $config['enable_withdraw']??0,
                'min' => $config['withdraw_min']??0,
                'max' => $config['withdraw_max']??0,
                'methods' => $new_mode,
                'service_fee' => $config['service_fee']??0,
                'enable_transfer' => $config['enable_transfer']??0,
                'withdraw_base_money'=>$config['withdraw_base_money']??0,
            ];
        }
    }

    /**
     * 获取日志字段数组
     */
    public function getLogAttribute($value)
    {
        $value = array_filter((array)json_decode($value, true));
        return (array)$value;
    }

    /**
     * 设置日志字段
     * @param mixed $value
     * @return string
     */
    public function setLogAttribute($value)
    {
        $val = is_object($value) || is_array($value) ? json_encode($value, JSON_UNESCAPED_UNICODE) : $value;
        $this->attributes['log'] = $val;
    }
}
